package com.onemile.net;

import java.util.Map;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Collections;
import java.util.WeakHashMap;
import java.lang.ref.SoftReference;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

import android.R.integer;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.widget.ImageView;
import android.os.Handler;
import android.os.Message;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import com.onemile.data.DXml;
import com.onemile.entity.Session;
import com.onemile.utils.UtiGZip;
import com.onemile.utils.UtiIO;

public class NetImageLoaderEX
{
   private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();
   private final LinkedList<Drawable> mChacheController = new LinkedList<Drawable>();
   private ExecutorService mThreadPool;
   private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());

   public static int MAX_CACHE_SIZE = 80;
   public int THREAD_POOL_SIZE = 3;

   /**
    * Constructor
    */
   public NetImageLoaderEX()
   {
	  mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
   }

   /**
    * Clears all instance data and stops running threads
    */
   public void Reset()
   {
	  ExecutorService oldThreadPool = mThreadPool;
	  mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
	  oldThreadPool.shutdownNow();

	  mChacheController.clear();
	  mCache.clear();
	  mImageViews.clear();
   }

   public void loadDrawable(final ImageView imageView, Drawable placeholder,final String id, final int type, final boolean isUseGZip)
   {
	  mImageViews.put(imageView,id);
	  Drawable drawable = getDrawableFromCache(id);

	  // check in UI thread, so no concurrency issues
	  if (drawable != null)
	  {
		 // Log.d(null, "Item loaded from mCache: " + url);
		 imageView.setImageDrawable(drawable);
	  }
	  else
	  {
		 imageView.setImageDrawable(placeholder);
		 queueJob(imageView, placeholder,id,type,isUseGZip);
	  }
   }

   private Drawable getDrawableFromCache(String id)
   {
	  if (mCache.containsKey(id))
	  {
		 return mCache.get(id).get();
	  }

	  return null;
   }

  
   private synchronized void putDrawableInCache(String id, Drawable drawable)
   {
	  int chacheControllerSize = mChacheController.size();
	  if (chacheControllerSize > MAX_CACHE_SIZE)
	  {
		 mChacheController.subList(0, MAX_CACHE_SIZE / 2).clear();
	  }
	  mChacheController.addLast(drawable);
	  mCache.put(id, new SoftReference<Drawable>(drawable));

   }

   private void queueJob(final ImageView imageView, final Drawable placeholder,final String id, final int type, final boolean isUseGZip)
   {
	  /* Create handler in UI thread. */
	  final Handler handler = new Handler()
	  {
		 @Override
		 public void handleMessage(Message msg)
		 {
			String tag = mImageViews.get(imageView);
			if (tag != null && tag.equals(id))
			{
			   if (imageView.isShown())
				  if (msg.obj != null)
				  {
					 imageView.setImageDrawable((Drawable) msg.obj);
				  }
				  else
				  {
					 imageView.setImageDrawable(placeholder);
				  }
			}
		 }
	  };

	  mThreadPool.submit(new Runnable()
	  {
		 @Override
		 public void run()
		 {
//			final Drawable bmp = downloadDrawable(url);
			
			final Drawable bmp=loadImageFromUrl(id, type, isUseGZip);
			putDrawableInCache(id, bmp);
			// if the view is not visible anymore, the image will be ready for
			// next time in cache
			if (imageView.isShown())
			{
			   Message message = Message.obtain();
			   message.obj = bmp;
			   handler.sendMessage(message);
			}
		 }
	  });
   }

   protected Drawable loadImageFromUrl(String id, int type, boolean isUseGZip)
   {
	  try
	  {
		 DXml data = null;
		 String field = null;
		 switch (type)
		 {
			case 1:
			   data = NetClient.GetCommoditySmallImage(id, isUseGZip);
			   field = "SmallCommodityImg";
			   break;
			case 2:
			   data = NetClient.GetCommodityBigImage(id, isUseGZip);
			   field = "CommodityImg";
			   break;
			case 3:
			   data = NetClient.GetShopBigImage(id, isUseGZip);
			   field = "ShopsImg";
			   break;
		 }

		 if (data != null)
		 {
			byte[] img = null;
			if (isUseGZip)
			{
			   img = UtiGZip.decompress(UtiIO.hexStringToBytes(data.getBody().GetFieldValue(field)));
			}
			else
			{
			   img = UtiIO.hexStringToBytes(data.getBody().GetFieldValue(field));
			}
			return Drawable.createFromStream(new ByteArrayInputStream(img), "src");
		 }
		 return null;
	  }
	  catch (Exception e)
	  {
		 if (Session.getInstance().IsDEBUG())
		 {
			Log.e("ERROR", "NetImageLoaderM_loadImageFromUrl(imageUrl) ", e);
		 }
	  }
	  return null;
   }
}
